import numpy as np
클래스 공부 5단계
-
지난시간까지 배운것: RPC자료형에 한정해서 print() 등의 기능을 조작할 수 있었다. (재정의 할 수 있었다.)
-
이번시간에 배울것: 특정자료형에 한정하여 print 이외의 파이썬 내부기능을 조작하여 보자. (재정의하여 보자)
motive
=1
a=2 b
type(a)
int
+b a
3
- a라는 인스턴스와 b라는 인스턴스를 + 라는 기호가 연결하고 있다.
=[1,2]
a=[3,4]
b+b a
[1, 2, 3, 4]
- a라는 인스턴스와 b라는 인스턴스를 + 라는 기호가 연결하고 있다.
-
동작이 다른 이유?
클래스를 배우기 이전: int자료형의
+
는 “정수의 덧셈”을 의미하고 list 자료형의+
는 “자료의 추가”를 의미한다.클래스를 배운 이후: 아마 클래스는
+
라는 연산을 정의하는 숨겨진 메소드가 있을 것이다. (print가 그랬듯이) 그런데 int 클래스에서는 그 메소드를 “정수의 덧셈”이 되도록 정의하였고 list클래스에서는 그 메소드를 “자료의 추가”를 의미하도록 정의하였다.
=1
a=2 b
__add__ a.
<method-wrapper '__add__' of int object at 0x70c560>
dir(a)
['__abs__',
'__add__',
'__and__',
'__bool__',
'__ceil__',
'__class__',
'__delattr__',
'__dir__',
'__divmod__',
'__doc__',
'__eq__',
'__float__',
'__floor__',
'__floordiv__',
'__format__',
'__ge__',
'__getattribute__',
'__getnewargs__',
'__gt__',
'__hash__',
'__index__',
'__init__',
'__init_subclass__',
'__int__',
'__invert__',
'__le__',
'__lshift__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__neg__',
'__new__',
'__or__',
'__pos__',
'__pow__',
'__radd__',
'__rand__',
'__rdivmod__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rfloordiv__',
'__rlshift__',
'__rmod__',
'__rmul__',
'__ror__',
'__round__',
'__rpow__',
'__rrshift__',
'__rshift__',
'__rsub__',
'__rtruediv__',
'__rxor__',
'__setattr__',
'__sizeof__',
'__str__',
'__sub__',
'__subclasshook__',
'__truediv__',
'__trunc__',
'__xor__',
'bit_length',
'conjugate',
'denominator',
'from_bytes',
'imag',
'numerator',
'real',
'to_bytes']
__add__(b) a.
3
__add__(a) b.
3
=[1,2]
a=[3,4] b
__add__(b) a.
[1, 2, 3, 4]
__add__(a) b.
[3, 4, 1, 2]
-
a+b는 사실 내부적으로 a.__add__(b)
의 축약구문이다. 따라서 먄악 a.__add__(b)
의 기능을 바꾸면 (재정의하면) a+b의 기능도 바뀔 것이다.
__add__
-
예제
class Student:
def __init__(self, age=20.0, semester=1):
self.age = age
self.semester = semester
print("입학을 축하합니다. 나이는 {}이고 현재 {}학기 입니다.".format(self.age, self.semester))
def __add__(self,val):
# val == 0: 휴학
# val == 1: 등록
if val==0:
self.age=self.age+0.5
elif val==1:
self.age=self.age+0.5
self.semester= self.semester+1
def _repr_html_(self):
= """
html_str 나이: {}<br/>
학기: {}<br/>
"""
return html_str.format(self.age, self.semester)
= Student() iu
입학을 축하합니다. 나이는 20.0이고 현재 1학기 입니다.
iu.semester
1
# 클래스가 저장되어있는 주소를 _repr_html_ 통해서 바꿔즘 iu
학기: 1
+ 1 #1학년 2학기 등록
iu iu
학기: 2
+ 0 # 휴학
iu iu
학기: 2
-
연산을 연속으로 하고 싶다.
+ 1 + 0 + 0 + 0 + 0 iu
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
-
에러의 이유?
1+1+1 #이거는 되는데?
3
1+1)+1 (
3
= (1+1)
_a type(_a)
int
+ 1 # 이 연산은 int인스턴스 + int인스턴스 _a
3
(안되는거)
+1+1 iu
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
=iu+1 _a
type(_a)
NoneType
+1 _a
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
-
에러를 해결하는 방법: iu+1의 결과로 Student 클래스의 인스턴스가 리턴되면 된다.
class Student:
def __init__(self, age=20.0, semester=1):
self.age = age
self.semester = semester
print("입학을 축하합니다. 나이는 {}이고 현재 {}학기 입니다.".format(self.age, self.semester))
def __add__(self,val):
# val == 0: 휴학
# val == 1: 등록
if val==0:
self.age=self.age+0.5
elif val==1:
self.age=self.age+0.5
self.semester= self.semester+1
return self
def _repr_html_(self):
= """
html_str 나이: {}<br/>
학기: {}<br/>
"""
return html_str.format(self.age, self.semester)
= Student() iu
입학을 축하합니다. 나이는 20.0이고 현재 1학기 입니다.
+ 1 # __add__의 return에 Student클래스의 인스턴스가 리턴되면서 자동으로 __repr_html_()실행 iu
학기: 4
+ 1 + 0 + 0 + 0 iu
학기: 5
__mul__
=1
a=1
b*b a
1
__mul__ a.
<method-wrapper '__mul__' of int object at 0x70c560>
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def _repr_html_(self):
= """
html_str 낼 수 있는 패: {} <br/>
기록: {}
"""
return html_str.format(self.candidate,self.actions)
=RPS()
a=RPS() b
a
기록: []
b
기록: []
- a*b 해서 승패를 확인하기 위한 클래스를 만들자
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
self.results = list()
def __mul__(self,other):
self.choose()
other.choose()if self.actions[-1]=='가위' and other.actions[-1]=='가위':
self.results.append(0)
0)
other.results.append(if self.actions[-1]=='가위' and other.actions[-1]=='바위':
self.results.append(-1)
1)
other.results.append(if self.actions[-1]=='가위' and other.actions[-1]=='보':
self.results.append(1)
-1)
other.results.append(if self.actions[-1]=='바위' and other.actions[-1]=='가위':
self.results.append(1)
-1)
other.results.append(if self.actions[-1]=='바위' and other.actions[-1]=='바위':
self.results.append(0)
0)
other.results.append(if self.actions[-1]=='바위' and other.actions[-1]=='보':
self.results.append(-1)
1)
other.results.append(if self.actions[-1]=='보' and other.actions[-1]=='가위':
self.results.append(-1)
1)
other.results.append(if self.actions[-1]=='보' and other.actions[-1]=='바위':
self.results.append(1)
-1)
other.results.append(if self.actions[-1]=='보' and other.actions[-1]=='보':
self.results.append(0)
0)
other.results.append(def choose(self):
self.actions.append(np.random.choice(self.candidate))
def _repr_html_(self):
= """
html_str 낼 수 있는 패: {} <br/>
액션: {} <br/>
승패: {}
"""
return html_str.format(self.candidate,self.actions,self.results)
=RPS()
a=RPS() b
a
액션: []
승패: []
b
액션: []
승패: []
for i in range(5):
*b a
a
액션: ['보', '바위', '가위', '가위', '바위']
승패: [1, 0, -1, 0, 1]
b
액션: ['바위', '바위', '바위', '가위', '가위']
승패: [-1, 0, 1, 0, -1]
숙제
RPS클래스에서 player a와 player b를 만들어라. Player a는 [‘가위’,‘보’] 중에 하나를 낼 수 있다. 그리고 Player b는 [‘가위’,‘바위’] 중에 하나를 낼 수 있다. 두 player는 가지고 있는 패를 (같은확률로) 랜덤으로 낸다. (즉 player a가 가위만 내거나 보만 내는 경우는 없다.)
누가 더 유리한가? 이유를 스스로 생각해보라. (이유를 정리하여 숙제로 제출할 필요 없음)
50000번의 시뮬레이션을 해보고 결과를 분석해보라.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
self.results = list()
def __mul__(self,other):
self.choose()
other.choose()if self.actions[-1]=='가위' and other.actions[-1]=='가위':
self.results.append(0)
0)
other.results.append(if self.actions[-1]=='가위' and other.actions[-1]=='바위':
self.results.append(-1)
1)
other.results.append(if self.actions[-1]=='보' and other.actions[-1]=='가위':
self.results.append(-1)
1)
other.results.append(if self.actions[-1]=='보' and other.actions[-1]=='바위':
self.results.append(1)
-1)
other.results.append(def choose(self):
self.actions.append(np.random.choice(self.candidate))
def _repr_html_(self):
= """
html_str 낼 수 있는 패: {} <br/>
액션: {} <br/>
승패: {}
"""
return html_str.format(self.candidate,self.actions,self.results)
=RPS(['가위','보'])
a=RPS(['가위','바위']) b
for i in range(50000):
*b a
sum(a.results)
-12358
sum(b.results)
12358